﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Forms = System.Windows.Forms;
using Microsoft.Win32;
using System.Threading;

namespace AzureBlob
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        private DateTime startTime;

        public MainWindow()
        {
            InitializeComponent();
            ShowProgress(0, 0, string.Empty);
            foreach (var accountInfo in SysTool.GetAccountList())
                AddAccountItem(accountInfo);
            AddAccountItem(AccountInfo.Development);
        }

        private void AddAccountItem(AccountInfo accountInfo)
        {
            var newTreeViewItem = new TreeViewItem();
            newTreeViewItem.Header = accountInfo.AccountName;
            newTreeViewItem.Tag = accountInfo;
            newTreeViewItem.HeaderTemplate = accountInfo.Connected ? Resources["AccountItemTemplate1"] as DataTemplate : Resources["AccountItemTemplate2"] as DataTemplate;
            newTreeViewItem.ContextMenu = Resources["AccountMenu"] as ContextMenu;
            if (AccountInfo.Development.Equals(accountInfo))
            {
                newTreeViewItem.Header = "(Development)";
            }
            int accountCount = treeView1.Items.Count;
            if (accountCount != 0 && AccountInfo.Development.Equals((treeView1.Items[accountCount - 1] as TreeViewItem).Tag))
                treeView1.Items.Insert(accountCount - 1, newTreeViewItem);
            else
                treeView1.Items.Add(newTreeViewItem);
            if (accountInfo.Connected)
                RefreshTreeView(newTreeViewItem);
        }

        private void FillContainerItems(TreeViewItem treeViewItem, ResultSegment<CloudBlobContainer> result)
        {
            if (result.HasMoreResults)
                result.BeginGetNext(async =>
                    FillContainerItems(treeViewItem, result.EndGetNext(async)), null);
            else
                ShowProgress(0, 0, string.Empty);

            AddContainerItems(treeViewItem, result.Results);
            
        }

        private void AddContainerItems(TreeViewItem treeViewItem, IEnumerable<CloudBlobContainer> iEnumerable)
        {
            if (!CheckAccess())
                Dispatcher.BeginInvoke(new Action<TreeViewItem, IEnumerable<CloudBlobContainer>>(AddContainerItems), treeViewItem, iEnumerable);
            else
            {
                treeViewItem.HeaderTemplate = Resources["AccountItemTemplate1"] as DataTemplate;
                foreach (var container in iEnumerable)
                    NewContainerTreeViewItem(treeViewItem, container);
            }
        }

        private void NewContainerTreeViewItem(TreeViewItem treeViewItem, CloudBlobContainer container)
        {
            TreeViewItem newTreeViewItem = new TreeViewItem();
            var holder = new CloudBlobContainerHolder(container);
            newTreeViewItem.Header = container.Name;
            newTreeViewItem.Tag = holder;
            newTreeViewItem.HeaderTemplate = GetContainerTamplate(holder);
            newTreeViewItem.ContextMenu = Resources["ContainerMenu"] as ContextMenu;
            newTreeViewItem.AllowDrop = true;
            newTreeViewItem.DragOver += new DragEventHandler(TreeViewItem_DragOver);
            newTreeViewItem.Drop += new DragEventHandler(TreeViewItem_Drop);
            treeViewItem.Items.Add(newTreeViewItem);
        }

        private DataTemplate GetContainerTamplate(CloudBlobContainerHolder holder)
        {
            string templateName;
            switch (holder.GetPermissions())
            {
                case BlobContainerPublicAccessType.Container:
                    templateName = "ContainerItemTemplate";
                    break;
                case BlobContainerPublicAccessType.Blob:
                    templateName = "ContainerItemTemplate1";
                    break;
                case BlobContainerPublicAccessType.Off:
                default:
                    templateName = "ContainerItemTemplate2";
                    break;
            }
            return Resources[templateName] as DataTemplate;
        }

        

        private void FillBlobItems(TreeViewItem treeViewItem, ResultSegment<IListBlobItem> result)
        {
            if (result.HasMoreResults)
                result.BeginGetNext(async =>
                    FillBlobItems(treeViewItem, result.EndGetNext(async)), null);
            else
                ShowProgress(0, 0, string.Empty);

            AddBlobItems(treeViewItem, result.Results);
        }

        private void AddBlobItems(TreeViewItem treeViewItem, IEnumerable<IListBlobItem> iEnumerable)
        {
            if (!CheckAccess())
                Dispatcher.BeginInvoke(new Action<TreeViewItem, IEnumerable<IListBlobItem>>(AddBlobItems), treeViewItem, iEnumerable);
            else
            {
                foreach (var blobItem in iEnumerable)
                {
                    if (blobItem is CloudBlockBlob)
                        listView1.Items.Add(new BlobInfo((CloudBlockBlob)blobItem));
                    else if (blobItem is CloudBlobDirectory)
                        NewDirectoryTreeViewItem(treeViewItem, (CloudBlobDirectory)blobItem);
                }
            }
        }

        private void NewDirectoryTreeViewItem(TreeViewItem treeViewItem, CloudBlobDirectory directory)
        {
            string tmpname = directory.Uri.Segments[directory.Uri.Segments.Count() - 1];
            string dirname = tmpname.Substring(0, tmpname.Length - 1); ;
            TreeViewItem newTreeViewItem = new TreeViewItem();
            newTreeViewItem.Header = dirname;
            newTreeViewItem.Tag = new CloudBlobDirectoryHolder(directory);
            newTreeViewItem.HeaderTemplate = Resources["FolderItemTemplate"] as DataTemplate;
            newTreeViewItem.ContextMenu = Resources["FolderMenu"] as ContextMenu;
            newTreeViewItem.AllowDrop = true;
            newTreeViewItem.DragOver += new DragEventHandler(TreeViewItem_DragOver);
            newTreeViewItem.Drop += new DragEventHandler(TreeViewItem_Drop);
            treeViewItem.Items.Add(newTreeViewItem);
        }

        

        private void RefreshTreeView(TreeViewItem treeViewItem)
        {
            if (!CheckAccess())
                Dispatcher.BeginInvoke(new Action<TreeViewItem>(RefreshTreeView), treeViewItem);
            else
            {
                

                if (treeViewItem.Tag is AccountInfo)
                {
                    AccountInfo accountInfo = (AccountInfo)treeViewItem.Tag;
                    treeViewItem.HeaderTemplate = Resources["AccountItemTemplate2"] as DataTemplate;
                    if (accountInfo.Connected)
                    {
                        accountInfo.Connected = false;

                        listView1.Items.Clear();
                        treeViewItem.Items.Clear();
                        treeViewItem.IsExpanded = true;
                        
                        var client = accountInfo.GetBlobClient();
                        client.BeginListContainersSegmented(async => 
                        {
                            try
                            {
                                FillContainerItems(treeViewItem, client.EndListContainersSegmented(async));
                                accountInfo.Connected = true;
                            }
                            catch (Exception)
                            {
                            }
                        }, null);
                    }
                }
                else if (treeViewItem.Tag is ICloudBlobHolder)
                {
                    ShowProgress(99, 100, "List files...");
                    listView1.Items.Clear();
                    treeViewItem.Items.Clear();
                    treeViewItem.IsExpanded = true;
                    ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;
                    //var list = holder.ListBlobs();
                    //AddBlobItems(treeViewItem, list);
                    //ShowProgress(0, 0, null);
                    holder.BeginListBlobsSegmented(async =>
                        FillBlobItems(treeViewItem, holder.EndListBlobsSegmented(async)), null);
                }
            }
        }

        private void SetStatus(string msg)
        {
            if (!CheckAccess())
                Dispatcher.BeginInvoke(new Action<string>(SetStatus), msg);
            else 
                statusLabel.Content = msg == null ? string.Empty : msg;
        }

        private void ShowProgress(double cur, double max, string msg)
        {
            if (!CheckAccess())
                Dispatcher.BeginInvoke(new Action<double, double, string>(ShowProgress), cur, max, msg);
            else
            {
                if (cur == 0)
                {
                    startTime = DateTime.Now;
                    inProgress = true;
                }
                progressBar1.Value = cur;
                progressBar1.Maximum = max;
                
                if (cur == max)
                {
                    progressBar1.Visibility = progressLabel.Visibility = remainLabel.Visibility = StopBtn.Visibility = Visibility.Collapsed;
                    inProgress = false;
                }
                else
                {
                    progressBar1.Visibility = progressLabel.Visibility = remainLabel.Visibility = StopBtn.Visibility = Visibility.Visible;
                    StopBtn.IsEnabled = true;
                    progressLabel.Content = SizeFormat(cur) + "/" + SizeFormat(max) + " " + string.Format("({0:F0}%)", cur / max * 100);
                    long span = DateTime.Now.Ticks - startTime.Ticks;
                    if (cur > 0)
                    {
                        long remain = (long)(span * max / cur - span);
                        remainLabel.Content = new TimeSpan(remain).ToString(@"hh\:mm\:ss");
                    }
                }
                SetStatus(msg);
            }
        }

        private string SizeFormat(double num)
        {
            if (num > 1000000000)
                return string.Format("{0:G3}G", num / 1000000000);
            else if (num > 1000000)
                return string.Format("{0:G3}M", num / 1000000);
            else if (num > 1000)
                return string.Format("{0:G3}K", num / 1000);
            else
                return string.Format("{0:G3}", num);
        }

        private void AddProgress(double delta, string msg)
        {
            if (!CheckAccess())
                Dispatcher.BeginInvoke(new Action<double, string>(AddProgress), delta, msg);
            else
            {
                ShowProgress(progressBar1.Value + delta, progressBar1.Maximum, msg);
            }
        }

        private void UploadFiles(TreeViewItem treeViewItem, ICloudBlobHolder holder, DirectoryInfo baseDirInfo, Queue<FileInfo> queue)
        {
            if (queue.Count() > 0 && inProgress)
            {
                FileInfo info = queue.Dequeue();
                string relUri = info.FullName.Substring(baseDirInfo.FullName.Length + 1);
                relUri = relUri.Replace('\\', '/');
                var blob = holder.GetBlockBlobReference(relUri);
                blob.Properties.ContentType = SysTool.GetContentType(info.Extension);
                FileStream fileStream = info.OpenRead();
                SetStatus("Upload " + info.FullName + "...");
                
                blob.BeginUploadFromStream(fileStream, async =>
                {
                    blob.EndUploadFromStream(async);
                    fileStream.Close();
                    AddProgress(info.Length, string.Empty);
                    UploadFiles(treeViewItem, holder, baseDirInfo, queue);
                }, null);
            }
            else
            {
                ShowProgress(0, 0, null);
                RefreshTreeView(treeViewItem);
            }
        }


        private void DownloadFiles(TreeViewItem treeViewItem, ICloudBlobHolder holder, DirectoryInfo dirInfo, Queue<IListBlobItem> queue)
        {
            if (queue.Count() > 0 && inProgress)
            {
                CloudBlockBlob blob = (CloudBlockBlob)queue.Dequeue();
                string relUri = blob.Uri.PathAndQuery.Substring(holder.Uri.PathAndQuery.Length);
                if (!relUri.StartsWith("/"))
                    relUri = '/' + relUri;
                relUri = UrlDecode(relUri.Replace('/', '\\'));
                FileInfo info = new FileInfo(dirInfo.FullName + relUri);
                MakeDirExist(info.Directory);
                FileStream fileStream = info.OpenWrite();
                SetStatus("Download " + blob.Uri.AbsoluteUri + "...");
                blob.BeginDownloadToStream(fileStream, async =>
                    {
                        blob.EndDownloadToStream(async);
                        fileStream.Close();
                        AddProgress(blob.Properties.Length, string.Empty);
                        DownloadFiles(treeViewItem, holder, dirInfo, queue);
                    }, null);
            }
            else
            {
                ShowProgress(0, 0, null);
                RefreshTreeView(treeViewItem);
            }
        }

        private void MakeDirExist(DirectoryInfo directoryInfo)
        {
            if (!directoryInfo.Exists)
            {
                MakeDirExist(directoryInfo.Parent);
                directoryInfo.Create();
            }
        }

        private void DeleteFiles(TreeViewItem treeViewItem, Queue<IListBlobItem> queue)
        {
            if (queue.Count() > 0 && inProgress)
            {
                CloudBlockBlob blob = (CloudBlockBlob)queue.Dequeue();
                SetStatus("Delete " + blob.Uri.AbsoluteUri + "...");
                blob.BeginDeleteIfExists(async =>
                {
                    blob.EndDeleteIfExists(async);
                    AddProgress(blob.Properties.Length, string.Empty);
                    DeleteFiles(treeViewItem, queue);
                }, null);
            }
            else
            {
                ShowProgress(0, 0, null);
                RefreshTreeView(treeViewItem);
            }
        }

        public string UrlDecode(string src)
        {
            StringBuilder builder = new StringBuilder();
            int p = 0, q;
            while (p < src.Length && (q = src.IndexOf('%', p)) != -1) {
                if (p != q)
                    builder.Append(src.Substring(p, q - p));
                if (src.Length - q > 3)
                    builder.Append((char)Int16.Parse(src.Substring(q + 1, 2), System.Globalization.NumberStyles.HexNumber));
                p = q + 3;
            }
            if (p < src.Length)
                builder.Append(src.Substring(p));
            string utf = builder.ToString();
            byte[] bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(utf);
            string result = Encoding.UTF8.GetString(bytes);
            return result;
        }

        private void UpdateContentType(TreeViewItem treeViewItem, ICloudBlobHolder holder, string contentType, Queue<IListBlobItem> queue)
        {
            if (queue.Count() > 0 && inProgress)
            {
                CloudBlockBlob blob = (CloudBlockBlob)queue.Dequeue();
                SetStatus("Update " + blob.Uri.AbsoluteUri + "...");
                blob.Properties.ContentType = contentType;
                
                blob.BeginSetProperties(async =>
                {
                    blob.EndSetProperties(async);
                    AddProgress(1, string.Empty);
                    UpdateContentType(treeViewItem, holder, contentType, queue);
                }, null);
            }
            else
            {
                ShowProgress(0, 0, null);
                RefreshTreeView(treeViewItem);
            }
        }

        private void UpdateCacheControl(TreeViewItem treeViewItem, ICloudBlobHolder holder, string cacheControl, Queue<IListBlobItem> queue)
        {
            if (queue.Count() > 0 && inProgress)
            {
                CloudBlockBlob blob = (CloudBlockBlob)queue.Dequeue();
                SetStatus("Update " + blob.Uri.AbsoluteUri + "...");
                blob.Properties.CacheControl = cacheControl;
                blob.BeginSetProperties(async =>
                {
                    blob.EndSetProperties(async);
                    AddProgress(1, string.Empty);
                    UpdateCacheControl(treeViewItem, holder, cacheControl, queue);
                }, null);
            }
            else
            {
                ShowProgress(0, 0, null);
                RefreshTreeView(treeViewItem);
            }
        }

        #region Context Menu

        private void TreeViewItem_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            e.Handled = true;
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            RefreshTreeView(treeViewItem);
        }

        private void NewAccount_Click(object sender, RoutedEventArgs e)
        {
            AccountSettingsDialog dlg = new AccountSettingsDialog(true);
            if (dlg.ShowDialog() == true)
            {
                var accountInfo = new AccountInfo(dlg.AccountName, dlg.AccountKey, dlg.CDN, false);
                AddAccountItem(accountInfo);
                SysTool.AddAccount(accountInfo.AccountName, accountInfo.AccountKey, accountInfo.CDN);
            }
        }

        private void Account_ContextMenu_Opened(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)e.Source;
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var accountInfo = (AccountInfo)treeViewItem.Tag;
            foreach (object item in cm.Items)
            {
                if (item is MenuItem)
                {
                    MenuItem menuItem = (MenuItem)item;
                    switch (menuItem.Name)
                    {
                        case "Conntect":
                            menuItem.IsEnabled = !accountInfo.Connected;
                            break;
                        case "Disconnect":
                        case "NewContainer":
                            menuItem.IsEnabled = accountInfo.Connected;
                            break;
                        case "EditAccount":
                        case "DeleteAccount":
                            menuItem.IsEnabled = !AccountInfo.Development.Equals(accountInfo);
                            break;
                    }
                }
            }
        }

        private void Connect_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var accountInfo = (AccountInfo)treeViewItem.Tag;
            accountInfo.Connected = true;
            
            RefreshTreeView(treeViewItem);
        }

        private void Disconnect_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var accountInfo = (AccountInfo)treeViewItem.Tag;
            accountInfo.Connected = false;
            treeViewItem.HeaderTemplate = Resources["AccountItemTemplate2"] as DataTemplate;
            treeViewItem.Items.Clear();
        }

        private void NewContainer_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;

            var dlg = new ContainerDialog();
            if (dlg.ShowDialog() == true)
            {
                string name = dlg.InputText;
                var accessType = dlg.GetAccessType();
                var accountInfo = (AccountInfo)treeViewItem.Tag;
                var client = accountInfo.GetBlobClient();
                var newContainer = client.GetContainerReference(name);
                newContainer.BeginCreateIfNotExist(async =>
                {
                    newContainer.EndCreateIfNotExist(async);
                    var permissions = newContainer.GetPermissions();
                    permissions.PublicAccess = accessType;
                    newContainer.SetPermissions(permissions);
                    RefreshTreeView(treeViewItem);
                }, null);
            }
        }

        private void EditAccount_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var accountInfo = (AccountInfo)treeViewItem.Tag;
            AccountSettingsDialog dlg = new AccountSettingsDialog(false)
            {
                AccountName = accountInfo.AccountName,
                AccountKey = accountInfo.AccountKey,
                CDN = accountInfo.CDN
            };
            
            if (dlg.ShowDialog() == true)
            {
                accountInfo.AccountKey = dlg.AccountKey;
                accountInfo.CDN = dlg.CDN;
                SysTool.SetAccount(accountInfo.AccountName, accountInfo.AccountKey, accountInfo.CDN);
            }

        }

        private void DeleteAccount_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;

            if (MessageBoxResult.Yes ==
                MessageBox.Show("Do you want to delete this account?", "Confirmation"
                    , MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No))
            {
                int index = 0;
                for (index = 0; index < treeView1.Items.Count; index++)
                    if (treeView1.Items[index].Equals(treeViewItem))
                        break;
                if (index < treeView1.Items.Count)
                {
                    var accountInfo = (AccountInfo)treeViewItem.Tag;
                    treeView1.Items.RemoveAt(index);
                    SysTool.RemoveAccount(index, accountInfo);
                }
            }
        }

        private void Container_ContextMenu_Opened(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)e.Source;
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var container = (CloudBlobContainerHolder)treeViewItem.Tag;
            var accessType = container.GetPermissions();
            foreach (object item in cm.Items)
            {
                if (item is MenuItem)
                {
                    MenuItem menuItem = (MenuItem)item;
                    switch (menuItem.Name)
                    {
                        case "PublicMenuItem":
                            menuItem.IsChecked = accessType == BlobContainerPublicAccessType.Container;
                            break;
                        case "BlobOnlyMenuItem":
                            menuItem.IsChecked = accessType == BlobContainerPublicAccessType.Blob;
                            break;
                        case "PrivateMenuItem":
                            menuItem.IsChecked = accessType == BlobContainerPublicAccessType.Off;
                            break;
                    }
                }
            }
        }

        private void Container_NewFolder_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            InputDialog dlg = new InputDialog() { Title = "New Folder", Message = "Input the new folder name. (The folder will be created temprary)" };
            if (dlg.ShowDialog() == true)
            {
                string name = dlg.InputText.Trim();
                var holder = (ICloudBlobHolder)treeViewItem.Tag;
                var newDirectory = holder.GetDirectoryReference(name);
                NewDirectoryTreeViewItem(treeViewItem, newDirectory);
            }
        }

        private void Holder_UploadFolder_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            
            var dlg = new Forms.FolderBrowserDialog();
            if (dlg.ShowDialog() == Forms.DialogResult.OK)
            {
                var holder = (ICloudBlobHolder)treeViewItem.Tag;
                var dirInfo = new DirectoryInfo(dlg.SelectedPath);
                var fileInfos = dirInfo.GetFiles("*", SearchOption.AllDirectories);
                var queue = new Queue<FileInfo>(fileInfos);
                var total = fileInfos.Sum(info => info.Length);
                ShowProgress(0, total, "Uploading...");
                UploadFiles(treeViewItem, holder, dirInfo, queue);
            }
        }

        private void Holder_DownloadFolder_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var dlg = new Forms.FolderBrowserDialog();
            if (dlg.ShowDialog() == Forms.DialogResult.OK)
            {
                var holder = (ICloudBlobHolder)treeViewItem.Tag;
                var dirInfo = new DirectoryInfo(dlg.SelectedPath);
                BlobRequestOptions option = new BlobRequestOptions() { UseFlatBlobListing = true };
                var queue = new Queue<IListBlobItem>(holder.ListBlobs(option));
                var total = queue.Sum(blob => ((CloudBlockBlob)blob).Properties.Length);
                ShowProgress(0, total, "Downloading...");
                DownloadFiles(treeViewItem, holder, dirInfo, queue);
            }
        }

        private void DeleteContainer_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            
            if (MessageBoxResult.Yes ==
                MessageBox.Show("Do you want to delete this container?", "Confirmation"
                    , MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No))
            {
                ShowProgress(99, 100, "List files...");
                var holder = (CloudBlobContainerHolder)treeViewItem.Tag;
                var parentTreeViewItem = (TreeViewItem)treeViewItem.Parent;
                holder.Delete();
                RefreshTreeView(parentTreeViewItem);
            }
        }

        private void Container_PublicMenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var holder = (CloudBlobContainerHolder)treeViewItem.Tag;
            holder.SetPermissions(BlobContainerPublicAccessType.Container);
            treeViewItem.HeaderTemplate = GetContainerTamplate(holder);
        }

        private void Container_BlobOnlyMenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var holder = (CloudBlobContainerHolder)treeViewItem.Tag;
            holder.SetPermissions(BlobContainerPublicAccessType.Blob);
            treeViewItem.HeaderTemplate = GetContainerTamplate(holder);
        }

        private void Container_PrivateMenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;
            var holder = (CloudBlobContainerHolder)treeViewItem.Tag;
            holder.SetPermissions(BlobContainerPublicAccessType.Off);
            treeViewItem.HeaderTemplate = GetContainerTamplate(holder);
        }


        private void DeleteFolder_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)ContextMenu.ItemsControlFromItemContainer((MenuItem)e.OriginalSource);
            TreeViewItem treeViewItem = (TreeViewItem)cm.PlacementTarget;

            if (MessageBoxResult.Yes ==
                MessageBox.Show("Do you want to delete this folder?", "Confirmation"
                    , MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No))
            {
                var holder = (ICloudBlobHolder)treeViewItem.Tag;
                BlobRequestOptions option = new BlobRequestOptions() { UseFlatBlobListing = true };
                var queue = new Queue<IListBlobItem>(holder.ListBlobs(option));
                var total = queue.Sum(blob => ((CloudBlockBlob)blob).Properties.Length);
                ShowProgress(0, total, "Deleting...");
                DeleteFiles(treeViewItem, queue);
            }
        }

        private void ListItemMenu_Opened(object sender, RoutedEventArgs e)
        {
            ContextMenu cm = (ContextMenu)e.Source;
            foreach (object item in cm.Items)
            {
                if (item is MenuItem)
                {
                    MenuItem menuItem = (MenuItem)item;
                    switch (menuItem.Name)
                    {
                        case "ViewInBrowser":
                            menuItem.IsEnabled = listView1.SelectedItems.Count == 1;
                            break;
                        case "ViewInBrowserCDN":
                            {
                                TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
                                while (!(treeViewItem.Tag is AccountInfo))
                                    treeViewItem = (TreeViewItem)treeViewItem.Parent;
                                AccountInfo accountInfo = (AccountInfo)treeViewItem.Tag;
                                menuItem.IsEnabled = listView1.SelectedItems.Count == 1 && accountInfo.CDN.Length > 0;
                                break;
                            }
                        case "DownloadFiles":
                        case "ChangeContentType":
                        case "DeleteFiles":
                            menuItem.IsEnabled = listView1.SelectedItems.Count > 0;
                            break;
                    }
                }
            }
        }

        private void ViewInBrowser_Click(object sender, RoutedEventArgs e)
        {
            BlobInfo blob = listView1.SelectedItem as BlobInfo;
            Uri url = blob.Uri;
            SysTool.ViewInBrowser(url.AbsoluteUri);
        }

        private void ViewInBrowserCDN_Click(object sender, RoutedEventArgs e)
        {
            BlobInfo blob = listView1.SelectedItem as BlobInfo;
            Uri url = blob.Uri;
            TreeViewItem treeItem = (TreeViewItem)treeView1.SelectedItem;
            while (!(treeItem.Parent is TreeView))
                treeItem = (TreeViewItem)treeItem.Parent;
            AccountInfo info = treeItem.Tag as AccountInfo;
            Uri cdnUrl = new Uri("http://" + info.CDN + url.PathAndQuery);
            SysTool.ViewInBrowser(cdnUrl.AbsoluteUri);
        }

        
        
        private void ListView_UploadFiles_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            if (treeViewItem == null || !(treeViewItem.Tag is ICloudBlobHolder))
                return;
            ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;

            var dlg = new OpenFileDialog();
            dlg.Multiselect = true;
            if (dlg.ShowDialog() == true && dlg.FileNames.Count() > 0)
            {
                var queue = new Queue<FileInfo>();
                foreach (var filename in dlg.FileNames)
                    queue.Enqueue(new FileInfo(filename));
                var total = queue.Sum(info => info.Length);
                ShowProgress(0, total, "Uploading...");
                UploadFiles(treeViewItem, holder, queue.First().Directory, queue);
            }
        }

        private void ListViewItem_DownloadFiles_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            if (treeViewItem == null || listView1.SelectedItems.Count == 0 || !(treeViewItem.Tag is ICloudBlobHolder))
                return;
            ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;

            var dlg = new Forms.FolderBrowserDialog();
            if (dlg.ShowDialog() == Forms.DialogResult.OK)
            {
                var dirInfo = new DirectoryInfo(dlg.SelectedPath);
                var queue = new Queue<IListBlobItem>();
                foreach (BlobInfo blobInfo in listView1.SelectedItems)
                    queue.Enqueue(blobInfo.Blob);
                var total = queue.Sum(blob => ((CloudBlockBlob)blob).Properties.Length);
                ShowProgress(0, total, "Downloading...");
                DownloadFiles(treeViewItem, holder, dirInfo, queue);
            }
        }

        private void ListViewItem_ChangeContentType_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            if (treeViewItem == null || listView1.SelectedItems.Count == 0 || !(treeViewItem.Tag is ICloudBlobHolder))
                return;
            ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;
            var dlg = new InputDialog() { Title = "Change Content Type", Message = "New content type:", InputText = ((BlobInfo)listView1.SelectedItem).ContentType };
            if (dlg.ShowDialog() == true)
            {
                string contentType = dlg.InputText.Trim();
                var queue = new Queue<IListBlobItem>();
                foreach (BlobInfo blobInfo in listView1.SelectedItems)
                    queue.Enqueue(blobInfo.Blob);
                ShowProgress(0, queue.Count(), "Chnaging content type...");
                UpdateContentType(treeViewItem, holder, contentType, queue);
            }
        }

        private void ListViewItem_ChangeCacheControl_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            if (treeViewItem == null || listView1.SelectedItems.Count == 0 || !(treeViewItem.Tag is ICloudBlobHolder))
                return;
            ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;
            var dlg = new CacheControlDialog() { CacheControlString = ((BlobInfo)listView1.SelectedItem).CacheControl };
            if (dlg.ShowDialog() == true)
            {
                string cacheControl = dlg.CacheControlString;
                var queue = new Queue<IListBlobItem>();
                foreach (BlobInfo blobInfo in listView1.SelectedItems)
                    queue.Enqueue(blobInfo.Blob);
                ShowProgress(0, queue.Count(), "Chnaging cache control...");
                UpdateCacheControl(treeViewItem, holder, cacheControl, queue);
            }
        }

        
        
        private void ListView_DeleteFiles_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            if (treeViewItem == null || listView1.SelectedItems.Count == 0 || !(treeViewItem.Tag is ICloudBlobHolder))
                return;
            ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;
            if (MessageBoxResult.Yes ==
                MessageBox.Show("Do you want to delete selected file(s)?", "Confirmation"
                    , MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No))
            {
                var queue = new Queue<IListBlobItem>();
                foreach (BlobInfo blobInfo in listView1.SelectedItems)
                    queue.Enqueue(blobInfo.Blob);
                var total = queue.Sum(blob => ((CloudBlockBlob)blob).Properties.Length);
                ShowProgress(0, total, "Deleting...");
                DeleteFiles(treeViewItem, queue);
            }
        }
        #endregion

        private void ListView1_DragOver(object sender, DragEventArgs e)
        {
            e.Handled = true;
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            bool accept = treeViewItem != null && !(treeViewItem.Tag is AccountInfo)
                && e.Data.GetDataPresent(DataFormats.FileDrop);
            e.Effects = accept ? DragDropEffects.Copy : DragDropEffects.None;
        }

        private void ListView1_Drop(object sender, DragEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)treeView1.SelectedItem;
            UploadDragFiles(treeViewItem, e.Data);
        }

        private void UploadDragFiles(TreeViewItem treeViewItem, IDataObject data)
        {
            if (treeViewItem == null || treeViewItem.Tag is AccountInfo)
                return;

            if (data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] filenames = (string[])data.GetData(DataFormats.FileDrop);
                ICloudBlobHolder holder = (ICloudBlobHolder)treeViewItem.Tag;
                var queue = new Queue<FileInfo>();
                DirectoryInfo baseDirInfo = null;
                foreach (string filename in filenames)
                {
                    FileInfo fileInfo = new FileInfo(filename);
                    if (fileInfo.Exists)
                    {
                        if (baseDirInfo == null)
                            baseDirInfo = fileInfo.Directory;
                        queue.Enqueue(fileInfo);
                    }
                    else
                    {
                        DirectoryInfo dirInfo = new DirectoryInfo(filename);
                        if (dirInfo.Exists)
                        {
                            if (baseDirInfo == null)
                                baseDirInfo = dirInfo.Parent;
                            var fileInfos = dirInfo.GetFiles("*", SearchOption.AllDirectories);
                            foreach (FileInfo info in fileInfos)
                                queue.Enqueue(info);
                        }
                    }
                }
                long total = queue.Sum(info => info.Length);
                ShowProgress(0, total, "Uploading...");
                UploadFiles(treeViewItem, holder, baseDirInfo, queue);
            }
        }

        //private void AsyncUploadFiles(TreeViewItem treeViewItem, ICloudBlobHolder holder, DirectoryInfo baseDirInfo, Queue<FileInfo> queue)
        //{
        //    if (queue.Count > 0 && inProgress)
        //    {
        //        new Thread(_AsyncUploadFiles).Start(new object[] {treeViewItem, holder, baseDirInfo, queue });
        //    }
        //    else
        //    {
        //        ShowProgress(0, 0, null);
        //        RefreshTreeView(treeViewItem);
        //    }
        //}

        //public void _AsyncUploadFiles(object data)
        //{
        //    object[] dataArray = (object[])data;
        //    TreeViewItem treeViewItem = (TreeViewItem)dataArray[0];
        //    ICloudBlobHolder holder = (ICloudBlobHolder)dataArray[1];
        //    DirectoryInfo baseDirInfo = (DirectoryInfo)dataArray[2];
        //    Queue<FileInfo> queue = (Queue<FileInfo>)dataArray[3];

        //    byte[] buf = new byte[512];
        //    int n;

        //    while (queue.Count > 0 && inProgress)
        //    {
        //        FileInfo info = queue.Dequeue();
        //        string relUri = info.FullName.Substring(baseDirInfo.FullName.Length + 1);
        //        relUri = relUri.Replace('\\', '/');
        //        var blob = holder.GetBlockBlobReference(relUri);
        //        blob.Properties.ContentType = SysTool.GetContentType(info.Extension);
        //        FileStream fileStream = info.OpenRead();
        //        SetStatus("Upload " + info.FullName + "...");

        //            while ((n = fileStream.Read(buf, 0, buf.Length)) != -1 && inProgress)
        //                if (n > 0)
        //                {
        //                    if (n == buf.Length)
        //                        blob.UploadByteArray(buf);
        //                    else
        //                    {
        //                        byte[] tempBuf = new byte[n];
        //                        Array.Copy(buf, tempBuf, n);
        //                        blob.UploadByteArray(tempBuf);
        //                    }
        //                    AddProgress(n, string.Empty);
        //                }

        //        fileStream.Close();
        //    }
        //    ShowProgress(0, 0, null);
        //}



        void TreeViewItem_DragOver(object sender, DragEventArgs e)
        {
            e.Handled = true;
            TreeViewItem treeViewItem = (TreeViewItem)e.Source;
            bool accept = treeViewItem != null && !(treeViewItem.Tag is AccountInfo)
                && e.Data.GetDataPresent(DataFormats.FileDrop);
            e.Effects = accept ? DragDropEffects.Copy : DragDropEffects.None;
        }

        void TreeViewItem_Drop(object sender, DragEventArgs e)
        {
            TreeViewItem treeViewItem = (TreeViewItem)e.Source;
            UploadDragFiles(treeViewItem, e.Data);
        }

        bool inProgress = false;
        private void StopBtn_Click(object sender, RoutedEventArgs e)
        {
            inProgress = false;
            StopBtn.IsEnabled = false;
        }
    }
}
